package com.baide.sanguanheyi.plc;

import com.baide.sanguanheyi.interfaces.PlcCallBack;
import com.baide.sanguanheyi.interfaces.PlcSendMsg;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

/**
 * @Author: create by DFX
 * @Date: 2020/4/23 20:46
 * @Version: V1.0.0
 * @Tips:
 */
@Component
public class NioServer implements Runnable, PlcSendMsg {

    @Autowired
    PlcConfig plcConfig;
    @Autowired
    NioServerHandler nioServerHandler;
    @Autowired
    NioObjectHandle nioObjectHandle;
    private Logger logger = LoggerFactory.getLogger(NioServer.class);
    PlcCallBack callBack;

    public void setCallBack(PlcCallBack callBack) {
        this.callBack = callBack;
        nioObjectHandle.setCallBack(callBack);
    }

    public void start() {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast("ping", new IdleStateHandler(600, 600, 600, TimeUnit.SECONDS));
                            pipeline.addLast("decoder", new StringDecoder(Charset.forName("UTF-8")));
                            pipeline.addLast("encoder", new StringEncoder(Charset.forName("UTF-8")));
                            pipeline.addLast("handler", nioServerHandler);
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(64, 2048, 65536)) // (5)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            // 绑定端口，同步等待成功
            ChannelFuture future = bootstrap.bind(plcConfig.getPort()).sync();
            if (future.isSuccess()) {
                logger.info(plcConfig.getPort() + "端口的服务器启动了");
            }
            // 等待服务监听端口关闭
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
            logger.info(plcConfig.getPort() + "端口的服务器被关闭了");
        }
    }

    @Override
    public void run() {
        start();
    }

    /**
     * @author create by DFX
     * @version v1.0.0
     * @tips 接受主线程发送移栽命令
     */
    @Override
    public void move(int plcNo, int position) {
        nioObjectHandle.move(plcNo, position);
    }

    /**
     * @author create by DFX
     * @version v1.0.0
     * @tips 接受上包站皮带停止命令
     */
    @Override
    public void start2Stop(int stop) {
        nioObjectHandle.start2Stop(stop);
    }

    /**
     * @author create by DFX
     * @version v1.0.0
     * @tips 接受线体启停命令
     */
    @Override
    public void line2Stop(int stop) {
        nioObjectHandle.line2Stop(stop);
    }

    @Override
    public void line2night(int stop) {
        nioObjectHandle.line2night(stop);
    }

    @Override
    public void stopAll() {
        nioObjectHandle.stopAll();
    }

    @Override
    public void sendMsg(String msg) {
        nioObjectHandle.sendMsg(msg);
    }

}
